package host

import (
	"fmt"
	"github.com/emicklei/go-restful"
	"kubeInstall/install"
	"kubeInstall/pkg/logger"
	"kubeInstall/server/handlers"
	cluster2 "kubeInstall/server/models/cluster"
	"kubeInstall/server/services/credential"
	"kubeInstall/server/services/host"
	"kubeInstall/utils/validate"
	"net/http"
	"strconv"
)

type hostHandler struct {
	handlers.BaseHandler
}

func NewHostHandler() handlers.IBaseHandler {
	return new(hostHandler)
}

func (h *hostHandler) AddToRoute(ws *restful.WebService) {

	ws.Route(ws.POST("/host").To(h.addHost))
	// get host
	ws.Route(ws.GET("/host/{host_id}").To(h.getHost))
	// list host
	ws.Route(ws.GET("/host").To(h.listHost))
	// delete host
	ws.Route(ws.DELETE("/host/{host_id}").To(h.deleteHost))
	// update host
	ws.Route(ws.PUT("/host/{host_id}").To(h.updateHost))
	logger.Info("add host module successfully")
}

func (h *hostHandler) getHost(r *restful.Request, resp *restful.Response) {

	hostId := r.PathParameter("host_id")
	if hostId == "" {
		h.RenderError(resp, fmt.Sprintf("get host id from http query failed!"), http.StatusNotFound)
		return
	}
	data, err := host.GetHost(hostId)

	if err != nil {
		h.RenderError(resp, fmt.Sprintf("get host failed! error is: %v", err), http.StatusNotFound)
		return
	}

	h.RenderResp(resp, data, http.StatusOK)

}

func (h *hostHandler) updateHost(r *restful.Request, resp *restful.Response) {

	hostId := r.PathParameter("host_id")
	if hostId == "" {
		h.RenderError(resp, fmt.Sprintf("get host id from http query failed!"), http.StatusNotFound)
		return
	}

	var req cluster2.Host

	if err := r.ReadEntity(&req); err != nil {
		h.RenderError(resp, fmt.Sprintf("read update info failed! error is:  %v", err), http.StatusBadRequest)
		return
	}

	if err := h.validateHost(req); err != nil {
		h.RenderError(resp, fmt.Sprintf("read host info failed. error is: %v", err), http.StatusBadRequest)
		return
	}

	if !credential.CheckCredentialIdIsValid(req.CredentialId) {
		h.RenderError(resp, fmt.Sprintf("credential_id %s not found", req.CredentialId), http.StatusBadRequest)
		return
	}

	/*
		if !models.CheckHostNameIsValid(req.HostName) {
			RenderError(resp, fmt.Sprintf("hostname %s already exsist", req.HostName), http.StatusBadRequest)
			return
		}

		if !models.CheckIpIsValid(req.IP) {
			RenderError(resp, fmt.Sprintf("ip %s already exsist", req.IP), http.StatusBadRequest)
			return
		}*/

	err := host.UpdateHost(hostId, &req)

	if err != nil {
		h.RenderError(resp, fmt.Sprintf("update host failed! error is:  %v", err), http.StatusBadRequest)
		return
	}

	data, _ := host.GetHost(hostId)
	h.RenderResp(resp, data, http.StatusOK)

}

func (h *hostHandler) addHost(r *restful.Request, resp *restful.Response) {

	var req cluster2.Host
	if err := r.ReadEntity(&req); err != nil {
		h.RenderError(resp, fmt.Sprintf("read host info failed! error is:  %v", err), http.StatusBadRequest)
		return
	}
	if err := h.validateHost(req); err != nil {
		h.RenderError(resp, fmt.Sprintf("read host info failed. error is: %v", err), http.StatusBadRequest)
		return
	}

	if !credential.CheckCredentialIdIsValid(req.CredentialId) {
		h.RenderError(resp, fmt.Sprintf("credential_id %s not found", req.CredentialId), http.StatusBadRequest)
		return
	}
	if !host.CheckHostNameIsValid(req.HostName) {
		h.RenderError(resp, fmt.Sprintf("hostname %s already exsist", req.HostName), http.StatusBadRequest)
		return
	}

	if !host.CheckIpIsValid(req.IP) {
		h.RenderError(resp, fmt.Sprintf("ip %s already exsist", req.IP), http.StatusBadRequest)
		return
	}
	cred, err := credential.GetCredential(req.CredentialId)
	if err != nil {
		h.RenderError(resp, fmt.Sprintf("add host: %s failed,error is:  %s",
			req.IP, err), http.StatusBadRequest)
		return
	}

	sshOpt := &install.SShOptions{
		User:   cred.Username,
		HostIp: req.IP,
		Port:   req.Port,
	}

	if cred.Type == "password" {
		sshOpt.Password = cred.CredentialData
	} else {
		sshOpt.PkFile = cred.CredentialData
	}

	if err, hostType := host.CheckHostIsActive(sshOpt); err != nil {
		h.RenderError(resp, fmt.Sprintf("connnect host: %s failed,error is:  %s",
			req.IP, err), http.StatusBadRequest)
		return

	} else {
		req.Status = true
		req.HostType = hostType
	}
	data, err := host.CreateHost(&req)

	if err != nil {
		h.RenderError(resp, fmt.Sprintf("add host failed. error is:%v", err), http.StatusBadRequest)
		return
	}
	h.RenderResp(resp, data, http.StatusOK)

}

func (h *hostHandler) validateHost(host cluster2.Host) error {
	if host.HostName == "" || host.CredentialId == "" {
		return fmt.Errorf("HostName or CredentialId can not be null")
	}

	if validate.IsContainIllegalChar(host.HostName, []string{",", "~", "#", "$", "%", "@"}) {
		return fmt.Errorf("username contains illegal characters")
	}

	if err := validate.ValidatePort(strconv.Itoa(host.Port)); err != nil {
		return err
	}

	if err := validate.ValidateIP(host.IP); err != nil {
		return err
	}

	return nil
}

func (h *hostHandler) deleteHost(r *restful.Request, resp *restful.Response) {

	hostid := r.PathParameter("host_id")
	if hostid == "" {
		h.RenderError(resp, " host id not found", http.StatusNotFound)
		return
	}

	err := host.DeleteHost(hostid)

	if err != nil {
		h.RenderError(resp, fmt.Sprintf("delete host failed! error is:  %v", err), http.StatusBadRequest)
		return
	}
	data := handlers.SuccessResp{
		StatusCode: http.StatusOK,
		Message:    fmt.Sprintf("Delete %s Success", hostid),
	}

	h.RenderResp(resp, data, http.StatusOK)

}

func (h *hostHandler) listHost(r *restful.Request, resp *restful.Response) {

	offset, _ := strconv.Atoi(r.QueryParameter("offset"))
	limit, _ := strconv.Atoi(r.QueryParameter("limit"))

	data, err := host.ListHosts(limit, offset)

	if err != nil {
		h.RenderError(resp, fmt.Sprintf("list host failed! error is:  %v", err), http.StatusBadRequest)
		return
	}
	h.RenderResp(resp, data, http.StatusOK)
}
